a11y(1.4.11): Checkbox — add ring-offset so the checked-state focus ring contrasts against the indigo checked background#3477
Merged
Conversation
…ing contrasts against the indigo checked background The Holocene Checkbox primitive's :checked state applied peer-checked:bg-interactive (--color-interactive-surface = indigo.600 in both modes) with a peer-focus-visible:ring-primary/70 focus ring, where ring-primary maps to --color-border-focus-info (also indigo.600 in both modes). The composited ring color equalled the checked background color (ratio 1.00:1), so the focus indicator was invisible whenever a checkbox was both checked and focused — the most common state for tab-traversing a form. This adds peer-focus-visible:ring-offset-2 + ring-offset-[var(--color- surface-primary)] on the visual surrogate. The 2 px gap sits between the indigo block and the indigo ring, and the gap is colored to match the surrounding page surface (white in light mode, black in dark mode) so the ring composites against canvas rather than against itself. Post-fix ratio against the gap is ~3.58:1 in light mode (Pass). Note: the existing Button-primary fix in #3438 used the class ring-offset-surface-primary, which is a silent no-op in the current Tailwind config (no surface-primary key in theme.ringOffsetColor or theme.colors). It worked there only because Tailwind's default --tw-ring-offset-color (#fff) happens to match light-mode surface-primary and is visible-but-mis-colored in dark mode. The arbitrary-value form used here, ring-offset-[var(--color-surface-primary)], passes the design token through verbatim and generates a real CSS rule that is correct in both modes. A separate follow-up may want to apply the same arbitrary- value treatment to Button. Cross-walks 2.4.7 Focus Visible (Level AA). Cascades to cloud-ui-main via the @temporalio/ui tarball on next repack. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
Contributor
|
10 tasks
ardiewen
approved these changes
May 29, 2026
13 tasks
rossedfort
added a commit
that referenced
this pull request
Jun 4, 2026
Auto-generated version bump from 2.50.0 to 2.51.0 Bump type: minor Changes included: - [`495e27f7`](495e27f) Use pageSize instead of maximumPageSize (#3422) - [`42c58c45`](42c58c4) fix: use rem-based width for expanded side-nav (#3426) - [`ce928ed5`](ce928ed) fix(a11y): meet 4.5:1 contrast for text-subtle and text-warning (WCAG 1.4.3) (#3437) - [`e8ed8a49`](e8ed8a4) fix(a11y): consistent high-contrast focus rings across all Button variants (WCAG 1.4.11) (#3438) - [`03918fb5`](03918fb) fix(a11y): prevent horizontal scroll on login page at 320px (WCAG 1.4.10) (#3440) - [`a11555fb`](a11555f) fix(a11y): use rem-based font-size and unitless line-height in markdown reset (#3430) - [`057ff323`](057ff32) fix: use empty alt on decorative SDK logo image (#3424) - [`e435ffd7`](e435ffd) Standalone Activity details page UI updates (#3427) - [`e09028f3`](e09028f) Make bottom-nav accept linksSnippet instead of sections (#3445) - [`a22a1e21`](a22a1e2) Add tooltip for SDK version (#3462) - [`c3b7820e`](c3b7820) [DT-4039] Workflow query builder doesn't work with numeric search attributes (#3435) - [`5e53881f`](5e53881) Make Common Errors dismissable (#3471) - [`2665e2f1`](2665e2f) [DT-4048] Add accessibility PR triage and notification helpers (#3465) - [`8083cf4e`](8083cf4) feat(DT-4017): Schedules List UI Update (#3467) - [`b5de30e3`](b5de30e) fix(markdown): allow nested lists to render as block (DT-4047) (#3463) - [`8a6fd2de`](8a6fd2d) Add a prop to hide select/deselect controls (#3474) - [`33ec1b3e`](33ec1b3) DT-4051: pre-populate input when starting standalone activity like this one (#3469) - [`0d64fc20`](0d64fc2) fix(a11y): reveal Copyable's CopyButton on focus-within (WCAG 2.1.1) (#3452) - [`321651c0`](321651c) fix: accept autocomplete prop on NumberInput, ChipInput, and Combobox (#3425) - [`6567c222`](6567c22) fix: cap ZoomSvg container height to viewport (#3428) - [`afd3a8ed`](afd3a8e) fix(a11y): accommodate text-spacing overrides on Badge and Chip (WCAG 1.4.12) (#3433) - [`d264b876`](d264b87) fix(a11y): non-color signal for Label required indicator (WCAG 1.4.1) (#3439) - [`73c61ea3`](73c61ea) fix(a11y): tabindex on <main> so the skip link moves focus reliably (WCAG 2.4.1) (#3451) - [`34e582a8`](34e582a) fix(a11y): info-and-relationships compliance (WCAG 1.3.1) (#3432) - [`f7be7b6c`](f7be7b6) fix(query): quote ExecutionDuration Go duration strings in visibility SQL (#3482) - [`9f0c2631`](9f0c263) Passthrough goto params to link component (#3483) - [`2f8c037b`](2f8c037) feat: add centerButton, menuButton, and linksContent snippets to BottomNavigation (#3485) - [`7f258bac`](7f258ba) fix: add "for" to validate connection modal title (#3488) - [`350397ab`](350397a) feat(DT-4069): Update modal backdrop to 50% opaque (#3486) - [`f01baa49`](f01baa4) refactor: Input & DatePicker - Svelte 5 & afterLabel snippet (#3479) - [`587c892f`](587c892) Fix decoded object payload summaries (#3491) - [`2b85ef06`](2b85ef0) fix(DT-4044): only use browser codec endpoint when override option is selected (#3490) - [`468893ba`](468893b) fix(a11y): improve 1.1.1 non-text content compliance (#3431) - [`3e8c996d`](3e8c996) fix(a11y): make Tooltip keyboard-accessible, dismissible, and hoverable (#3429) - [`47552538`](4755253) fix(a11y): name-role-value compliance, partial (WCAG 4.1.2) (#3434) - [`e2c95d54`](e2c95d5) fix(a11y): align DOM order with visual order in mobile bottom-nav (WCAG 1.3.2) (#3441) - [`634b08e1`](634b08e) a11y(1.4.11): focus rings — lighten dark-mode --color-border-focus-info to indigo.400 so ring-primary/70 meets 3:1 against surface-primary (#3478) - [`039a555a`](039a555) a11y(1.4.11): Checkbox — add ring-offset so the checked-state focus ring contrasts against the indigo checked background (#3477) - [`01161e2e`](01161e2) a11y(1.4.10): activity-options drawer — make width responsive so it reflows at 320 px (#3476) - [`99f0a0a4`](99f0a0a) fix(a11y): filter hidden nav items in mobile bottom-nav (WCAG 4.1.2) (#3494) - [`d12ebacc`](d12ebac) fix(a11y): add focusin/focusout to saved-query nav hover tooltip (WCAG 2.1.1) (#3453) - [`c7206af9`](c7206af) fix(a11y): render a warning icon for Chip warning intent (WCAG 1.4.1) (#3450) - [`b64ed713`](b64ed71) fix(a11y): pair Toast variant background with a severity icon (WCAG 1.4.1) (#3449) - [`8e2ef708`](8e2ef70) upgrade temporal api version to latest (v1.62.13) (#3502) Co-authored-by: rossedfort <11775628+rossedfort@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description & motivation 💭
The Holocene
Checkboxprimitive renders its:checkedstate with an indigo background (peer-checked:bg-interactive→--color-interactive-surface= indigo.600#444CE7in both modes persrc/lib/theme/variables.ts:124-127) and applies apeer-focus-visible:ring-2 peer-focus-visible:ring-primary/70focus ring.ring-primarymaps to--color-border-focus-info= indigo.600 in both modes (src/lib/theme/plugin.ts:221,variables.ts:213-216).When a checkbox is checked and focused, Tailwind composites a 2 px ring whose color is indigo.600 at 70% alpha directly on top of an indigo.600 background. Effective ring color equals background color, contrast ratio ~1.00 : 1, focus indicator invisible. Keyboard users tabbing through a form lose the focus indicator the moment a checkbox is checked.
The unchecked-state ring is unaffected (it composites over
surface-primary, not over indigo). This PR fixes the checked-state-only failure by adding a 2 px ring-offset between the indigo background and the indigo ring, so the ring composites against the surrounding canvas (surface-primary) rather than against itself.The diff:
Two lines in
src/lib/holocene/checkbox.svelte, inside the!disabledclass array of the visual-surrogate<span>.Design-system finding to surface to reviewers. The arbitrary-value form
ring-offset-[var(--color-surface-primary)]is used here rather than the bare classring-offset-surface-primary. The latter is a silent no-op in the current Tailwind config:src/lib/theme/plugin.tsextendstheme.ringColorwithprimary/danger/success/brandbut does NOT extendtheme.ringOffsetColor, and the basetheme.colorspalette has nosurface-primarykey. I verified empirically withpnpm exec tailwindcssagainst both class strings —ring-offset-surface-primarygenerates zero CSS rules (falls back to default#fff);ring-offset-[var(--color-surface-primary)]generates--tw-ring-offset-color: var(--color-surface-primary)correctly. The previously-merged Button-primary focus-ring fix (#3438) uses the bare-class form — it works in light mode by coincidence (default#fffmatches light-mode surface-primary) and is visible-but-mis-colored in dark mode. This PR uses the arbitrary-value form so dark mode is also correct. A separate follow-up may want to migrate Button to the same form; that's out of scope here.Composes with PR #3478. PR #3478 (in flight) shifts the dark-mode value of
--color-border-focus-infofrom indigo.600 to indigo.400 soring-primary/70composites at 3.78:1 against dark canvas. That fix addresses what color the ring is. This PR addresses where the ring sits (offset). Together they bring the dark-mode focused-and-checked checkbox to ~8.43:1 ring-vs-canvas contrast. They're independent and can land in either order.Screenshots (if applicable) 📸
Screenshots to be captured by the PR author from the Vercel preview build (link appears once the
Vercelcheck passes). Include light-mode and dark-mode captures for each affected primitive.Design Considerations 🎨
The rendered checkbox now has slightly more visual weight when focused-and-checked (4 px total of ring + gap vs the previous 2 px ring overlapping the block). For unchecked + focused, no visual change. Design team may want to confirm the focused-and-checked rendering is acceptable; it's necessary to meet WCAG 1.4.11 because the underlying indigo-on-indigo overlap is what makes the ring invisible.
Testing 🧪
How was this tested 👻
Automated checks performed locally on
a11y/1.4.11-checkbox-checked-focus-ringbefore pushing:pnpm lint— 0 errorspnpm check(svelte-check) — 0 errors (84 pre-existing warnings repo-wide, none incheckbox.svelte)pnpm test -- --run— 142 test files / 2023 tests passlint-staged: eslint --fix, prettier --write, stylelint --fix) clean on the modified filepnpm exec tailwindcss) confirmsring-offset-[var(--color-surface-primary)]emits real CSS (--tw-ring-offset-color: var(--color-surface-primary))Manual visual testing in Storybook is the responsibility of the PR author after the preview deploy is ready (see "Steps for others to test" below).
Steps for others to test: 🚶🏽♂️🚶🏽♀️
pnpm installif needed.pnpm stories:dev— open Storybook at http://localhost:6006.!disabledarray).main— the offset is a visual no-op here because the checkbox background already equals surface-primary.Checklists
Draft Checklist
src/lib/holocene/checkbox.svelte(inside the!disabledclass array)pnpm exec tailwindcssprobering-offset-surface-primaryin current config) surfaced in PR descriptionpnpm lint,pnpm check,pnpm test -- --runall passMerge Checklist
Issue(s) closed
A11y-Audit-Ref: 1.4.11-checkbox-checked-focus-ring
Closes the checkbox checked-state focus-ring defect documented in the May 2026 audit (manifest bucket 1, severity serious, scope ui-main). See
scripts/a11y/manifest.ymlfor the canonical entry.Docs
Any docs updates needed?
No external docs (
docs.temporal.io) need updating — this is a consumer-side class addition with no API surface change.🤖 Generated with Claude Code